#include<bits/stdc++.h>
//#include<atcoder/all>
using namespace std;
//using namespace atcoder;
typedef int64_t ll;
//using mint=modint998244353;
typedef unsigned long ulong;
typedef long double ld;
const ll MODA=998244353;
ll vx[4]={0,1,0,-1};
ll vy[4]={1,0,-1,0};
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
long long gcd(long long a,long long b){
a=abs(a);
b=abs(b);
ll gcdmax=max(a,b);
ll gcdmin=min(a,b);
if(gcdmin==0)return gcdmax;
while(true){
if(gcdmax%gcdmin==0)break;
else gcdmax%=gcdmin;
swap(gcdmin,gcdmax);
}
return gcdmin;
}
ll pow(ll N,ll P,ll M){
if(P==0)return 1;
else if(P%2==0){
ll t=pow(N,P/2,M);
return t*t%M;
}
else return N*pow(N,P-1,M)%M;
}
ll pow(ll N,ll P){
if(P==0)return 1;
else if(P%2==0){
ll t=pow(N,P/2);
return t*t;
}
else return N*pow(N,P-1);
}
vector<ll> fac;
vector<ll> finv;
vector<ll> inv;
void COMinit(ll N,ll P){
rep(i,N+1){
if(i==0){
fac.push_back(1);
finv.push_back(1);
inv.push_back(1);
}
else if(i==1){
fac.push_back(1);
finv.push_back(1);
inv.push_back(1);
}
else{
fac.push_back(fac.at(i-1)*i%P);
inv.push_back(P-inv.at(P%i)*(P/i)%P);
finv.push_back(finv.at(i-1)*inv.at(i)%P);
}
}
}
ll COM(ll n,ll k,ll P){
if(n<k)return 0;
if(n<0||k<0)return 0;
return fac.at(n)*(finv.at(k)*finv.at(n-k)%P)%P;
}
struct UnionFind {
vector<ll> par; // par[i]:iの親の番号 (例) par[3] = 2 : 3の親が2
UnionFind(ll N) : par(N) { //最初は全てが根であるとして初期化
for(ll i = 0; i < N; i++) par[i] = i;
}
ll root(ll x) { // データxが属する木の根を再帰で得る:root(x) = {xの木の根}
if (par[x] == x) return x;
return par[x] = root(par[x]);
}
void unite(ll x, ll y) { // xとyの木を併合
ll rx = root(x); //xの根をrx
ll ry = root(y); //yの根をry
if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時:xの根rxをyの根ryにつける
}
bool same(ll x, ll y) { // 2つのデータx, yが属する木が同じならtrueを返す
ll rx = root(x);
ll ry = root(y);
return rx == ry;
}
};
const ulong MASK30 = (1UL << 30) - 1;
const ulong MASK31 = (1UL << 31) - 1;
const ulong MOD = (1UL << 61) - 1;
const ulong MASK61 = MOD;
//mod 2^61-1を計算する関数
ulong CalcMod(ulong x)
{
ulong xu = x >> 61;
ulong xd = x & MASK61;
ulong res = xu + xd;
if (res >= MOD) res -= MOD;
return res;
}
//a*b mod 2^61-1を返す関数(最後にModを取る)
ulong Mul(ulong a, ulong b)
{
ulong au = a >> 31;
ulong ad = a & MASK31;
ulong bu = b >> 31;
ulong bd = b & MASK31;
ulong mid = ad * bu + au * bd;
ulong midu = mid >> 30;
ulong midd = mid & MASK30;
return CalcMod(au * bu * 2 + midu + (midd << 31) + ad * bd);
}
int main(){
ll N;
cin>>N;
vector<string> S(N);
map<pair<ulong,ll>,int> mp;
ll v=0;
mt19937_64 rng(time(0));
ulong base= rng() % MOD;
ulong base2 =rng()%MODA;
rep(i,N){
cin>>S[i];
v+=S[i].size();
ulong hs=0;
ulong hs2=0;
rep(j,S[i].size()){
ulong c=(S[i][j]-'a');
c++;
hs=CalcMod(Mul(hs,base)+c);
hs2=CalcMod(Mul(hs2,base2)+c);
mp[{hs,hs2}]++;
}
}
ll ans=2*N*v;
rep(i,N)reverse(S[i].begin(),S[i].end());
rep(i,N){
cin>>S[i];
v+=S[i].size();
ulong hs=0;
ulong hs2=0;
rep(j,S[i].size()){
ulong c=(S[i][j]-'a');
c++;
hs=CalcMod(Mul(hs,base)+c);
hs2=CalcMod(Mul(hs2,base2)+c);
ans-=2*mp[{hs,hs2}];
}
}
cout<<ans<<endl;
}
1609A - Divide and Multiply | 149B - Martian Clock |
205A - Little Elephant and Rozdil | 1609B - William the Vigilant |
978B - File Name | 1426B - Symmetric Matrix |
732B - Cormen --- The Best Friend Of a Man | 1369A - FashionabLee |
1474B - Different Divisors | 1632B - Roof Construction |
388A - Fox and Box Accumulation | 451A - Game With Sticks |
768A - Oath of the Night's Watch | 156C - Cipher |
545D - Queue | 459B - Pashmak and Flowers |
1538A - Stone Game | 1454C - Sequence Transformation |
165B - Burning Midnight Oil | 17A - Noldbach problem |
1350A - Orac and Factors | 1373A - Donut Shops |
26A - Almost Prime | 1656E - Equal Tree Sums |
1656B - Subtract Operation | 1656A - Good Pairs |
1367A - Short Substrings | 87A - Trains |
664A - Complicated GCD | 1635D - Infinite Set |